package com.zhajh.socket;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.SystemClock;

import com.zhajh.MyApp;
import com.zhajh.utils.Const;
import com.zhajh.utils.PackData;

public class SocketClient {
    IoConnector connector = new NioSocketConnector();
    IoSession session = null;
    ClientHandler mClientHandler = null;

    public SocketClient(){
        //connector.setConnectTimeout(5);
        // 添加过滤器
        connector.getFilterChain().addLast(
				"flash",
				new ProtocolCodecFilter(new ActionScriptObjectFactory(Charset
						.forName("UTF-8"))));
        // 添加业务逻辑处理器类
        mClientHandler = new ClientHandler(connector.getManagedSessions());
        connector.setHandler(mClientHandler);
    }

    public boolean connect(String host, int port)
    {
        // 连接
    	try
    	{
    		ConnectFuture future = connector.connect(new InetSocketAddress(host, port));
    		future.awaitUninterruptibly();// 等待连接创建完成
    		session = future.getSession();
    		return true;
    	}
    	catch (Exception e)
    	{
    		e.printStackTrace();
    		return false;
    	}
    }

    public boolean isConnected()
    {
    	return (session != null);
    }

    public void closeSocket(){
    	if (session == null)
    	{
    		return;
    	}

    	session.close();
    	session.getCloseFuture().awaitUninterruptibly();// 等待连接断开
        connector.dispose();
        session = null;
    }

    /*************************************************
     * 数据格式:
     * 0~3: int, 数据长度
     * 4~7: int, 接口id
     * 8~: 返回的数据
     * @param funcId
     * @param data
     * @return
     */
    public JSONObject getResult(int funcId, IoBuffer buf)
    {
    	int fId = buf.getInt();

    	if (fId != funcId)
    	{
    		return null;
    	}

    	String txt = null;
    	byte[] data = new byte[buf.remaining()];
    	buf.get(data);
    	txt = new String(data);

		if (txt != null)
		{
			try
			{
				JSONObject object = new JSONObject(txt);
				return object;
			} catch (JSONException e) {
	            e.printStackTrace();
	        }
		}

		return null;
    }

    /*****************************************************
     * @param data
     * @param bNeedAck: 是否需要回应
     * @return
     */
    private IoBuffer sendData(int funcId, String param, boolean bNeedAck){
    	if (session == null)
    	{
    		return null;
    	}

    	if (bNeedAck)
    	{
    	    mClientHandler.setAckFuncId(funcId);
    	}

    	int len = Const.VERSION_CODE_LEN+Const.FUNC_ID_LEN;
    	byte[] data = null;

    	if (param != null)
    	{
    		data = param.getBytes();
    		len += data.length;
    	}

    	PackData pkg = new PackData(len);
    	pkg.writeInt(MyApp.getVersionCode());
    	pkg.writeInt(funcId);

    	if (data != null)
    	{
    		pkg.writeBytes(data);
    	}

    	session.write(pkg);

    	if (bNeedAck)
    	{
    	    IoBuffer buf = null;

    		while ((buf=mClientHandler.getAck()) == null)
    		{
    			SystemClock.sleep(200);
    		}

    		return buf;
    	}

        return null;
    }

    public JSONObject logon(String username, String passwd, String deviceId, String deviceModel)
    {
    	JSONObject obj = new JSONObject();
    	String param = null;

    	try {
    		obj.put("username", username);
			obj.put("passwd", passwd);
			obj.put("device_id", deviceId);
			obj.put("device_model", deviceModel);
			param = obj.toString();
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}

		IoBuffer ack = sendData(Const.FUNC_LOGON, param, true);

		if (ack == null)
		{
			return null;
		}

		return getResult(Const.FUNC_LOGON, ack);
    }

    public JSONObject findTable()
    {
		IoBuffer ack = sendData(Const.FUNC_FAST_FIND_SEAT, null, true);

		if (ack == null)
		{
			return null;
		}

		return getResult(Const.FUNC_FAST_FIND_SEAT, ack);
    }

    public void setMsgCallback(ClientHandler.MsgCallback cb)
    {
        mClientHandler.setMsgCallback(cb);
    }

    public void readyPlay()
    {
		sendData(Const.FUNC_READY_PLAY, null, false);
    }
}
